package com.leetcode;

/**
 * 下一个序列
 *
 * 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地，如果数组的所有排列根据其字典顺序从小到大排列在一个容器中，
 * 那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。
 * 如果不存在下一个更大的排列，那么这个数组必须重排为字典序最小的排列（即，其元素按升序排列）。
 *
 * @author winson
 * @create 2022-03-31 10:23
 */
public class NextPermutationSolution {

    /**
     * 必须 原地 修改，只允许使用额外常数空间。
     * 从后往前遍历数组，找到第一个较小元素，满足nums[i] < nums[i-1]，此时(i+1 - nums.length - 1)是降序
     * 从后往前找一个大于nums[i]的较大数nums[j]，交换两个数，然后对i+1 - nums.length - 1的元素进行降序
     * @param nums
     */
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        if (i >= 0) {
            // 当前值不是最大值，查找较大数
            int j = nums.length - 1;
            while (j >= 0 && nums[i] >= nums[j]) {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
    }

    /**
     * 交换数组元素
     * @param nums
     * @param i
     * @param j
     */
    public void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    /**
     * 双指针反转数组
     * @param nums
     * @param start
     */
    public void reverse(int[] nums, int start) {
        int left = start, right = nums.length - 1;
        while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
        }
    }

    public static void main(String[] args) {
        NextPermutationSolution solution = new NextPermutationSolution();
        int[] nums = new int[]{1,2,3};
        /**
         * 输入：nums = [1,2,3]
         * 输出：[1,3,2]
         */
        solution.nextPermutation(nums);
    }
}
